home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / shrink_names < prev    next >
Encoding:
Internet Message Format  |  1987-02-18  |  10.7 KB

  1. Subject:  v08i074:  Shrink VeryLong+File.names to shorter names
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: simon2 <simon2@its63b.ed.ac.uk>
  6. Mod.sources: Volume 8, Issue 74
  7. Archive-name: shrink_names
  8.  
  9. [  Blame me for the Makefile.  --r$  ]
  10.  
  11. Here is a very useful program for changing filenames from BSD filename
  12. form to a more portable form (14 char limit).  It is reasonably
  13. intelligent as to what the structure of the original filename was, and
  14. tries quite hard to maintain this underlying structure by just
  15. shortening the subfields.
  16.     Simon Brown
  17.     Department of Computer Science, University of Edinburgh, Scotland.
  18.     ...!{ihnp4,seismo,decvax}!mcvax!ukc!cstvax(!its63b?)!simon
  19.  
  20. ------------------------- CUT HERE -------------------------------
  21. #! /bin/sh
  22. # This is a shell archive, meaning:
  23. # 1. Remove everything above the #! /bin/sh line.
  24. # 2. Save the resulting text in a file.
  25. # 3. Execute the file with /bin/sh (not csh) to create:
  26. #    shrink.1
  27. #    shrink.c
  28. #    Makefile
  29. export PATH; PATH=/bin:/usr/bin:$PATH
  30. echo shar: "extracting 'shrink.1'" '(2814 characters)'
  31. if test -f 'shrink.1'
  32. then
  33.     echo shar: "will not over-write existing file 'shrink.1'"
  34. else
  35. cat << \SHAR_EOF > 'shrink.1'
  36. .TH SHRINK 1 "Edinburgh University" "December 1986"
  37. .SH NAME
  38. shrink \- generate short filenames from extended ones
  39. .SH SYNOPSIS
  40. .B shrink
  41. [ -vnSm ] [ -s\fIseparators\fR ] [ -\fIn\fR ] \fIfilename\fR ...
  42. .SH DESCRIPTION
  43. .I Shrink
  44. converts a filename to a shrunken form, suitable for transportation
  45. to another system with less generous filename length limits.
  46. It takes each
  47. .I filename
  48. given, and applies certain rules to shorten it, if necessary.
  49. In particular, it tries to leave suffixes unchanged, and,
  50. to a less extent, to keep the initial component as close to the
  51. original as possible. Of course, very long suffixes do have to be
  52. truncated.
  53. .PP
  54. The following options are recognized:
  55. .TP
  56. .B -v
  57. Verbose mode. Normally
  58. .I shrink
  59. does its work silently, but under the verbose option it chats about
  60. what decisions its making.
  61. .TP
  62. .B -n
  63. Normally the new filename is generated so as to not clash with an
  64. existing file, to prevent several long-named files folding into the
  65. same shortened form. This behaviour can be revoked by use of the
  66. .B -n
  67. option.
  68. .TP
  69. .B -s
  70. Normally the new filename is printed on the standard output.
  71. The
  72. .B -s
  73. option causes 
  74. .I shrink
  75. to be silent.
  76. This is useful only in conjunction with the
  77. .B -m
  78. option.
  79. .TP
  80. .B -m
  81. This causes the files to be physically renamed;
  82. normally, just the ``suggested'' change is printed but nothing
  83. actually done.
  84. .TP
  85. .B "-s \fIseparators\fB"
  86. This can be used to change the set of
  87. .I separators
  88. that 
  89. .I shrink
  90. recognizes.
  91. These are the characters that are used to delimit filename components.
  92. .I Shrink
  93. operates by shrinking characters out of each component
  94. (though it is loath to modify the first or last components unless
  95. it has no choice), while leaving the delimiters unchanged.
  96. However, if a filename contains a vast number of delimiter characters
  97. (such as
  98. .I this_file_contains_quite_a_lot_of_stuff_and_useful_stuff_at_that
  99. ), then some components (and their associated delimiters)
  100. will have to be deleted totally.
  101. The default delimiter set is
  102. .BR + ,
  103. .BR - ,
  104. .BR . ,
  105. .BR _ ,
  106. .BR ~ 
  107. and
  108. .BR , .
  109. .TP
  110. .B "-\fIn\fB"
  111. A numerical flag \fIn\fR may be given to specify a maximum length
  112. that the resultant filename is allowed to be.
  113. The default is 14 (which is the maximum file length under all unix
  114. systems without the Berkeley modified filesystem).
  115. .SH DIAGNOSTICS
  116. Under the
  117. .B -v
  118. option, lots of diagnostics can be produced.
  119. Those preceded by the word
  120. .B "``warning:''"
  121. can probably be ignored.
  122. .PP
  123. Under certain circumstances, 
  124. .I shrink
  125. may refuse totally to deal with some filenames,
  126. though this is not very likely to occur unless a very small
  127. maximum length flag is specified.
  128. .SH BUGS
  129. If the file begins with a delimiter character,
  130. then 
  131. .I shrink
  132. sometimes causes the shortened filename to be shorter than it
  133. need be.
  134. This is not too serious a bug.
  135. .SH AUTHOR
  136. Simon Brown.
  137. SHAR_EOF
  138. fi
  139. echo shar: "extracting 'shrink.c'" '(6420 characters)'
  140. if test -f 'shrink.c'
  141. then
  142.     echo shar: "will not over-write existing file 'shrink.c'"
  143. else
  144. cat << \SHAR_EOF > 'shrink.c'
  145. /*
  146.  *    Rename a file so's it will be unique under systems without
  147.  *    extended filename size.
  148.  *    The new name is written on the stardard output.
  149.  *
  150.  *    Example:
  151.  *        To copy lots of files from a 4.?BSD system to a
  152.  *        SystemV, SystemIII, 2.?BSD or V7 system, without
  153.  *        having to worry about overlapping filenames
  154.  *        (eg, so "what_a_long_filename.c" and "what_a_long_filename.h"
  155.  *        don't get squished), just do
  156.  *            for i in *
  157.  *            do
  158.  *                j=`shrink -m $i`
  159.  *                uucp $j othersys!/stuff/$j  (or rcp, hhcp, ...)
  160.  *            done
  161.  *
  162.  *    Bug:    It gets overenthusiastic and deletes characters
  163.  *            unnecessarily if the filename begins with a "."
  164.  *
  165.  *    Author:
  166.  *        Simon Brown
  167.  *        Department of Computer Science, University of Edinburgh.
  168.  */
  169.  
  170. #include <stdio.h>
  171.  
  172. /*
  173.  *    maximum no. of "segments" allowed in a file 
  174.  */
  175. #define MAXSEGS 10
  176.  
  177. /*
  178.  *    silly names for strchr/strrchr under non-usg unices
  179.  */
  180. #ifndef sysV
  181. #define strchr    index
  182. #define strrchr    rindex
  183. #endif sysV
  184.  
  185. char *getsegment();
  186. char *strchr(), *strrchr();
  187.  
  188. struct segment {
  189.     char seg_string[63];
  190.     char seg_sep;
  191. } seg[MAXSEGS];
  192.  
  193. char defaults[] = "._+-,@~=";
  194. char usagemsg[] = "Usage: %s [-<maxlength>] [-mnSv] [-s<separators>] filename ...\n";
  195.  
  196. int max = 14;            /* target length */
  197. int nocheck = 0;        /* don't check for existance (-n flag) */
  198. int chatty = 0;            /* talk a lot (-v flag) */
  199. int silent = 0;            /* don't say anything (-s flag) */
  200. int move = 0;            /* rename file (-m flag) */
  201. char *file, *prefix;
  202. int modified = 0;
  203. char realname[512];
  204. char *separators = defaults;
  205.  
  206. main(argc,argv)
  207. char **argv;
  208. {
  209.     register int i, j;
  210.     int nsegs, suflen, remainder, delete;
  211.     int total;
  212.     int zap = 0;
  213.     register char *op;
  214.     char *progname = argv[0];
  215.  
  216.     if (argv[1] == (char *)0){
  217.         fprintf(stderr, usagemsg, progname);
  218.         exit(1);
  219.     }
  220.     while (*++argv)        /* process command-line options... */
  221.         if (**argv=='-')
  222.             while (*++*argv)
  223.                 switch(**argv){
  224.                    case '0': case '1': case '2':
  225.                    case '3': case '4': case '5':
  226.                    case '6': case '7': case '8':
  227.                    case '9':    /* change target length */
  228.                     max = atoi(*argv);
  229.                     if (max<=0){
  230.                         fprintf(stderr,"%s: illegal length %s\n", argv[0], argv[1]);
  231.                         exit(1);
  232.                     }
  233.                     while (*++*argv);
  234.                     --*argv;
  235.                     break;
  236.                    case 's':    /* change separator definition */
  237.                     separators = ++*argv;
  238.                     while (*++*argv);
  239.                     --*argv;
  240.                     break;
  241.                    case 'n':    /* don't create a uniquely named file */
  242.                     nocheck=1;
  243.                     break;
  244.                    case 'v':    /* talk a lot */
  245.                     chatty=1;
  246.                     break;
  247.                    case 'm':     /* move files */
  248.                     move=1;
  249.                     break;
  250.                    case'S':    /* silent */
  251.                     silent=1;
  252.                     break;
  253.                    default:
  254.                     fprintf(stderr,usagemsg,progname);
  255.                     exit(1);
  256.                 }
  257.         else break;
  258.     while (*argv){
  259.         strcpy(realname, *argv);
  260.         if (prefix=strrchr(*argv,'/')){        /* dir/.../file */
  261.             file=prefix+1;
  262.             *prefix = '\0';
  263.             prefix = *argv;
  264.         } else file = *argv;
  265.         argv++;
  266.         op=file;
  267.         modified=0;
  268.         /* split into logical parts */
  269.         for (i=0; i<MAXSEGS && (op=getsegment(op,i)); i++);
  270.         if (i==MAXSEGS){
  271.             fprintf(stderr,"%s: too many segments\n", file);
  272.             continue;
  273.         }
  274.         nsegs = i-1;
  275.         if ((nsegs*2) >= max){
  276.             fprintf(stderr,"%s: too many segments\n", file);
  277.             continue;
  278.         }
  279.         suflen = strlen(seg[nsegs].seg_string);
  280.         if (suflen>max-nsegs-1){
  281.             if (chatty)
  282.                 fprintf(stderr,"warning: %s: suffix truncated\n", file);
  283.             suflen = max-(2*nsegs)-1;
  284.             seg[nsegs].seg_string[suflen-1] = '\0';
  285.             modified=1;
  286.         } else if (suflen+nsegs > max-nsegs-1){
  287.             zap = nsegs - (max-suflen)/2;
  288.             if (chatty && zap)
  289.                 fprintf(stderr,"warning: %s: %d segments removed\n", file, zap);
  290.         }
  291.         if (nsegs>=1){        /* complicated filename */
  292.             for (i=zap+1; i<=nsegs; i++)
  293.                 if (seg[i].seg_sep) suflen++;
  294.             if (seg[0].seg_sep) suflen++;
  295.             remainder = max - suflen;
  296.             delete = remainder/nsegs;
  297.             total = suflen;
  298.             for (i=zap+1; i<nsegs; i++){
  299.                 if (strlen(seg[i].seg_string) > delete)
  300.                     modified=1;
  301.                 seg[i].seg_string[delete] = '\0';
  302.                 total += delete;
  303.             }
  304.             if (strlen(seg[0].seg_string) > max-total)
  305.                 modified=1;
  306.             seg[0].seg_string[max-total] = '\0';
  307.         }
  308.         unique(zap,nsegs,modified);
  309.     }
  310. }
  311.  
  312. /*
  313.  *    get a segment from a filename.
  314.  *    returns pointer to remainder of filename, or 0 at end of filename
  315.  */
  316. char *
  317. getsegment(cp,i)
  318. char *cp;
  319. {
  320.     register char *xp = seg[i].seg_string;
  321.     while (*cp && strchr(separators,*cp)==0)
  322.         *xp++ = *cp++;
  323.     *xp = '\0';
  324.     seg[i].seg_sep = *cp;
  325.     if (*cp) cp++;
  326.     if (seg[i].seg_string[0] || seg[i].seg_sep) return(cp);
  327.     else return((char *)0);
  328. }
  329.  
  330.     
  331. /*
  332.  *    print out the current filename in a unique form
  333.  */
  334. unique(zap,n,mod)
  335. {
  336.     register int i, j;
  337.     int jmax[MAXSEGS];
  338.     int xstart, xstop;
  339.  
  340.     if (ok(zap,zap||mod)) return;
  341.     xstart = (n==0)? 0 : 1;
  342.     xstop = (n==0)? 1 : n;
  343.     more:
  344.     if (xstop <= xstart){
  345.         xstart=0;
  346.         xstop = n+1;
  347.     }
  348.     for (i=xstart; i<xstop; i++)
  349.         jmax[i] = strlen(seg[i].seg_string);
  350.     for (j=0; j<5; j++){
  351.         for (i=xstart; i<xstop; i++){
  352.             if (j >= jmax[i]) continue;
  353.             increment(seg[i].seg_string,j);
  354.             if (ok(zap,1)) return;
  355.         }
  356.     }
  357.     if (xstart>0 || xstop<n+1){    /* Desparation time: try _any_ segment! */
  358.         xstop = -1;
  359.         goto more;
  360.     }
  361.     fprintf(stderr,"Can't generate unique name for %s\n", file);
  362. }
  363.  
  364. /*
  365.  *    modify a character in a string (stupid algorithm)
  366.  */
  367. increment(str,ind)
  368. char *str;
  369. {
  370.     char ch = str[ind];
  371.  
  372.     if (ch>='a' && ch<='z') ch += ('A'-'a');
  373.     else if (ch>='A' && ch<='Z') ch += ('a'-'A');
  374.     str[ind] = ch;
  375. }
  376.  
  377.  
  378. /*
  379.  *    see if a filename is reasonable, and if so print it out
  380.  *    and return 1.
  381.  *    otherwise return 0.
  382.  */
  383. ok(zap,changed)
  384. {
  385.     char buffer[512];
  386.     register char *cp = buffer;
  387.     register char *xp;
  388.     register int i;
  389.  
  390.     if (prefix){
  391.         for (xp=prefix; *xp; )
  392.             *cp++ = *xp++;
  393.         *cp++ = '/';
  394.     }
  395.     for (xp=seg[0].seg_string; *xp; )    /* copy initial segment */
  396.         *cp++ = *xp++;
  397.     if (seg[0].seg_sep){
  398.         *cp++ = seg[0].seg_sep;
  399.         for (i=zap+1; ; i++){        /* copy rest of segments */
  400.             for (xp=seg[i].seg_string; *xp; )
  401.                 *cp++ = *xp++;
  402.             if (seg[i].seg_sep) *cp++ = seg[i].seg_sep;
  403.             else if (seg[i].seg_string[0] == '\0') break;
  404.         }
  405.     }
  406.     *cp = '\0';
  407.     if (changed && nocheck==0 && access(buffer,0)==0){
  408.         if (chatty)
  409.             fprintf(stderr,"warning: %s already exists - trying again\n",buffer);
  410.         return(0);
  411.     } else {
  412.         if (silent==0) printf("%s\n", buffer);
  413.         if (move && strcmp(realname,buffer)){
  414.             if (link(realname,buffer)==-1 || unlink(realname)==-1)
  415.                 fprintf(stderr,"%s: link/unlink failure\n", realname);
  416.         }
  417.         return(1);
  418.     }
  419. }
  420.  
  421.  
  422. SHAR_EOF
  423. fi
  424. if test -f 'Makefile'
  425. then
  426.     echo shar: "will not over-write existing file 'Makefile'"
  427. else
  428. cat << \SHAR_EOF > 'Makefile'
  429. CFLAGS=-O
  430. shrink: shrink.c
  431.     $(CC) $(CFLAGS) -o shrink shrink.c
  432. install: shrink
  433.     @echo copy shrink.1 and shrink to appropriate directories
  434. SHAR_EOF
  435. fi
  436. exit 0
  437. #    End of shell archive
  438. --
  439.